package org.example;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;

public class MiniApplicationContext {
    private Map<String, Object> beans = new HashMap<>();
    private Map<String, Object> beansWithDestroyMethod = new HashMap<>();

    public void loadBeans(String xmlFile) {
        try {
            File file = new File(xmlFile);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(file);

            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getElementsByTagName("bean");

            for (int i = 0; i < nodeList.getLength(); i++) {
                Element beanElement = (Element) nodeList.item(i);
                String beanId = beanElement.getAttribute("id");
                String beanClass = beanElement.getAttribute("class");

                // 处理构造函数注入
                NodeList constructorArgNodes = beanElement.getElementsByTagName("constructor-arg");
                List<Object> constructorArgs = new ArrayList<>();
                for (int j = 0; j < constructorArgNodes.getLength(); j++) {
                    Element constructorArgElement = (Element) constructorArgNodes.item(j);
                    String argType = constructorArgElement.getAttribute("type");
                    String argValue = constructorArgElement.getAttribute("value");
                    constructorArgs.add(getValueOfType(argType, argValue));
                }

                // 处理属性注入
                NodeList propertyNodes = beanElement.getElementsByTagName("property");
                Map<String, Object> properties = new HashMap<>();
                for (int j = 0; j < propertyNodes.getLength(); j++) {
                    Element propertyElement = (Element) propertyNodes.item(j);
                    String propertyName = propertyElement.getAttribute("name");
                    String propertyType = propertyElement.getAttribute("type");
                    String propertyValue = propertyElement.getAttribute("value");
                    properties.put(propertyName, getValueOfType(propertyType, propertyValue));
                }

                // 使用反射创建 Bean，支持构造函数注入
                Class<?> clazz = Class.forName(beanClass);
                Object beanInstance;

                if (!constructorArgs.isEmpty()) {
                    Constructor<?> constructor = clazz.getConstructor(constructorArgs.stream().map(Object::getClass).toArray(Class[]::new));
                    beanInstance = constructor.newInstance(constructorArgs.toArray());
                } else {
                    beanInstance = clazz.newInstance();
                }

                // 注入属性
                for (Map.Entry<String, Object> entry : properties.entrySet()) {
                    String propertyName = entry.getKey();
                    Object propertyValue = entry.getValue();

                    Field field = clazz.getDeclaredField(propertyName);
                    field.setAccessible(true);
                    field.set(beanInstance, propertyValue);
                }

                // 处理 init-method
                String initMethod = beanElement.getAttribute("init-method");
                if (!initMethod.isEmpty()) {
                    Method init = clazz.getMethod(initMethod);
                    init.invoke(beanInstance);
                }

                // 注册 destroy-method 的执行
                String destroyMethod = beanElement.getAttribute("destroy-method");

                if (!destroyMethod.isEmpty()) {
                    beansWithDestroyMethod.put(beanId, beanInstance);
                }

                // 将 Bean 存放到容器中
                beans.put(beanId, beanInstance);
            }

            // 容器构建成功，输出成功消息
            System.out.println("Container built successfully.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String beanId) {
        return beans.get(beanId);
    }

    public void destroyBeans() {
        for (Map.Entry<String, Object> entry : beansWithDestroyMethod.entrySet()) {
            Object beanInstance = entry.getValue();
            Class<?> clazz = beanInstance.getClass();
            String destroyMethod = beans.get(entry.getKey()).getClass().getAnnotation(BeanDefinition.class).destroyMethod();

            if (!destroyMethod.isEmpty()) {
                try {
                    Method destroy = clazz.getMethod(destroyMethod);
                    destroy.invoke(beanInstance);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Object getValueOfType(String type, String value) {
        if ("int".equals(type) || "Integer".equals(type)) {
            return Integer.parseInt(value);
        } else if ("long".equals(type) || "Long".equals(type)) {
            return Long.parseLong(value);
        } else if ("double".equals(type) || "Double".equals(type)) {
            return Double.parseDouble(value);
        } else if ("boolean".equals(type) || "Boolean".equals(type)) {
            return Boolean.parseBoolean(value);
        } else {
            return value;
        }
    }
}
